#ifndef _Ring_QUEUE_HPP_
#define _Ring_QUEUE_HPP_

#include <iostream>
#include <vector>
#include <pthread.h>
#include <cstdlib>
#include <ctime>
#include <sys/types.h>
#include <unistd.h>
#include "sem.hpp"

const int g_dedault_num = 5;

// 多生产多消费的意义在哪里？  不要狭隘的认为，把任务和数据放在交易场所，就是生产和消费了。
// 将数据或者任务生产前和拿到之后处理，才是最耗时时间的
// 生产的本质：私有的任务 -> 公共空间中
// 消费的本质：公共空间中的任务 -> 私有的

// 信号量的本质是一个计数器？ 计数器的意义是什么？?   可以不用进入临界区，就可以得知资源的情况，甚至可以减少临界区内部的判断
// 申请锁 -> 判断与访问 -> 释放锁 --> 本质是我们并不清楚临界资源的情况！！
// 信号量要提前预设资源 的情况，而且在pv变化过程中，我们可以在外部就能知晓临界资源的情况！
// 

template<class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_dedault_num)
        :ring_queue_(default_num)
        ,num_(default_num)
        ,c_step(0)
        ,p_step(0)
        ,space_sem_(default_num) // 信号量,开始时,空间资源是满的
        ,data_sem_(0) // 信号量,开始时,数据是空的
    {
        pthread_mutex_init(&clock,nullptr);
        pthread_mutex_init(&plock,nullptr);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }

    //  生产者: 空间资源,生产者们的临界资源是什么？
    void Push(const T& in)
    {
        // 先申请信号量(0),再加锁(1)
        space_sem_.P(); // 申请信号量
        pthread_mutex_lock(&plock);  // ?
        // 一定是竞争成功的生产者 -- 就一个！
        ring_queue_[p_step++] = in;
        p_step %= num_;
        pthread_mutex_unlock(&plock);
        data_sem_.V(); // 有数据,进行V操作
    }
    
    // 消费者；数据资源,消费者们的临界资源是什么？
    void Pop(T* out)
    {
        data_sem_.P();
        pthread_mutex_lock(&clock);
        // 一定是竞争成功的消费者 -- 就一个！
        *out = ring_queue_[c_step++];
        c_step %= num_;
        pthread_mutex_unlock(&clock);
        space_sem_.V();
    }

    // void debug()
    // {
    //     std::cerr << "num: " << ring_queue_.size() << " num: " << num << std::endl;
    // }
private:
    std::vector<T> ring_queue_;
    int num_;
    int c_step; // 消费下标
    int p_step; // 生产下标
    Sem space_sem_;
    Sem data_sem_;
    pthread_mutex_t clock;
    pthread_mutex_t plock;
};


#endif
